#!/bin/bash
# Create a benchmark output for the prover in HTML and TeX format into html/.
# @author Zoltan Kovacs <zoltan@geogebra.org>

# Setting defaults.
MY_VERSION=2.1

IMGHEIGHT=25
HTML=html/all.html
TEX=html/all.tex
CSV=none
# Don't use this, it is just an example:
COLUMNS="DesktopInternal DesktopGrobcov Web Node Wasm"
TESTGGBURLBASE_GGBDIR=http://dev.geogebra.org/trac/browser/trunk/geogebra/test/scripts/benchmark/art-plotter
GEOGEBRAWEB_URL1=https://www.geogebra.org/classic/?filename=https://dev.geogebra.org/trac/export
GEOGEBRAWEB_URL2=trunk/geogebra/test/scripts/benchmark/art-plotter
SINGULARWSREMOTEURL=http://singularws.idm.jku.at/
DOTS=20
NICEHTML=1

COMMANDLINE="$0 $*"

usage() {
 echo "$0 - a benchmarking tool for GeoGebra's ART plotter subsystem"
 echo "Usage:"
 echo " xvfb-run $0 [options]"
 echo "  where options can be as follows (defaults in parentheses):"
 echo "   -H <number>  image height: show .ggb thumbnails in the given number of pixels ($IMGHEIGHT)"
 echo "   -b <number>  use build number instead of the latest one for all columns"
 echo "   -o <file>    set name for output .html file ($HTML)"
 echo "   -T <file>    set name for output .tex file ($TEX)"
 echo "   -c <list>    space separated list of prover engines to show as columns ($COLUMNS)"
 echo "   -g <url>     use 'url' for putting links on test cases ($TESTGGBURLBASE_GGBDIR)"
 echo "   -s <url>     use 'url' to use non-default SingularWS ($SINGULARWSREMOTEURL)"
 echo "   -d <length>  use dots in test names in LaTeX output if the name is longer than length ($DOTS)"
 echo "   -N           do not use nice HTML output (similarly to LaTeX)"
 echo "   -h           show this help"
 echo "   -v           print script version"
 echo
 exit 0
 }

version() {
 echo "$0 version $MY_VERSION"
 exit 0
 }

while getopts "H:o:T:c:d:b:Nehv" OPT; do
 case $OPT in
  H)
   IMGHEIGHT="$OPTARG"
   ;;
  N)
   NICEHTML=0
   ;;
  o)
   HTML="$OPTARG"
   ;;
  d)
   DOTS="$OPTARG"
   ;;
  T)
   TEX="$OPTARG"
   ;;
  c)
   COLUMNS="$OPTARG"
   ;;
  g)
   TESTGGBURLBASE_GGBDIR="$OPTARG"
   ;;
  b)
   BUILD_NUMBER="$OPTARG"
   ;;
  h)
   usage
   ;;
  v)
   version
   ;;

 esac
done

# Put name of the filters into $@
shift $((OPTIND-1))

if [ "$BUILD_NUMBER" = "" ]; then
 BUILD_NUMBER=`sqlite3 sqlite3db "select max(build_number) from builds"`
 fi

COLUMNSNO=`echo $COLUMNS | wc -w`
THISDIR=`dirname $0`
MYDIR=`cd $THISDIR; pwd`
mkdir -p $MYDIR/tmp $MYDIR/html
LOGFILE=$MYDIR/tmp/.test.log
rm -f $HTML $TEX

# Title
TITLE="ART plotter benchmark for GeoGebra $BUILD_NUMBER"
DATE=`date "+%Y-%m-%d %H:%M"`
SVN_REVISION=`sqlite3 sqlite3db "select svn_revision from builds where build_number=$BUILD_NUMBER"`
BUILD_URL=`sqlite3 sqlite3db "select build_url from builds where build_number=$BUILD_NUMBER"`
HOST=`sqlite3 sqlite3db "select machine from builds where build_number=$BUILD_NUMBER"`
echo "<!DOCTYPE html><html><head>
<title>$TITLE</title>
<link rel=\"stylesheet\" type=\"text/css\" href=\"style.css\">
</head><body><h1>$TITLE</h1>
<h2>on $DATE at $HOST</h2>" >> $HTML
cp style.css `dirname $HTML`
echo "% Generated by '$COMMANDLINE' on $DATE.
% This file could be converted to PDF by using pdflatex.
\documentclass{article}
\usepackage[table]{xcolor}
\usepackage{multirow}
\usepackage{longtable}
\usepackage{array}
\begin{document}
\scriptsize{" >> $TEX

echo "<table><tr><th rowspan=\"2\" colspan=\"2\">Test file</th>" >> $MYDIR/$HTML

# Header
RESULTCOLUMN="m{1cm}"
echo "\begin{longtable}{|l|*{$COLUMNSNO}{${RESULTCOLUMN}r|}}
\hline
{\multirow{2}{*}{\bf Test}}" >> $MYDIR/$TEX

for c in $COLUMNS; do
 j=`echo $c | cut -f1 -d,`
 r=`echo $c | cut -s -f2- -d,`

 TOPRINT=`echo $j | sed s/"_"/" "/`
 if [ "$r" = "" ]; then
  FOOTHTML=""
  FOOTTEX=""
 else
  FOOTHTML="<br>$r"
  FOOTTEX="\\footnote{$r}"
  fi
 echo "<th colspan=\"2\">$TOPRINT$FOOTHTML</th>" >> $MYDIR/$HTML
 echo "& \multicolumn{2}{c|}{\bf $TOPRINT$FOOTTEX}" >> $MYDIR/$TEX
 done
echo "</tr><tr>" >> $MYDIR/$HTML
echo "\\\\" >> $MYDIR/$TEX

cn=0
declare -A COL_BUILD_NUMBER
declare -A COL_J
declare -A COL_R

# Creating column header related data
for c in $COLUMNS; do
 echo "<th>deg</th><th>FPS</th>" >> $MYDIR/$HTML
 echo "&deg&FPS" >> $MYDIR/$TEX
 cn=$((cn+1))
 j=`echo $c | cut -f1 -d,`
 r=`echo $c | cut -s -f2- -d,`
 ndg=0
 build_number=$BUILD_NUMBER
 echo $r | grep --silent p && {
  PREV=`echo $r | awk '{i=index($0,"p"); print(substr($0,i+1))}'`
  build_number=`sqlite3 sqlite3db "select build_number from builds order by build_number desc limit 1 offset $PREV"`
  }
 echo $r | grep --silent b && {
  build_number=`echo $r | awk '{i=index($0,"b"); print(substr($0,i+1))}'`
  }
 COL_J[$cn]=$j
 COL_BUILD_NUMBER[$cn]=$build_number
 done

echo "</tr>" >> $MYDIR/$HTML
echo "\\\\ \hline" >> $MYDIR/$TEX

# Content
TESTS=0
ALLGOOD_NO=0
ALLGOOD_SUM=0
for t in `sqlite3 sqlite3db "select distinct testcase from tests where build_number=$BUILD_NUMBER"`; do
 echo -en "Processing test case $t...\033[K\015"
 ALLGOOD=1
 TESTS=`expr $TESTS + 1`
 # Creating thumbnail:
 cd $MYDIR
 i=`find -name $t.ggb`
 TEST=`basename "$i"`
 unzip $i geogebra_thumbnail.png >/dev/null 2>&1
 mv geogebra_thumbnail.png html/$TEST.png
 # TODO: change "latest" to current revision:
 echo "<tr><td class=\"ex\"><a href=\"$TESTGGBURLBASE_GGBDIR/$i\">$TEST</a></td><td class=\"eximg\"><a href=\"${GEOGEBRAWEB_URL1}/latest/${GEOGEBRAWEB_URL2}/$i#\"><img src=\"$TEST.png\" height=${IMGHEIGHT}></a></td>" >> $MYDIR/$HTML
 TEST=`echo $TEST | sed s/".ggb"//`

 if [ `expr ${#TEST} '>' $DOTS` = 1 ]; then
  TEST=${TEST:0:10}\$\\ldots\$${TEST:(-2)}
  fi
 echo "\cellcolor{blue!10}$TEST " | sed s/".ggb"// >> $MYDIR/$TEX

 declare -A RESULTDATA
 declare -A RESULTCLASSDATA
 declare -A CELLCOLORDATA
 declare -A TEXTCOLORDATA
 declare -A TIMEDATA
 declare -A FPSDATA
 declare -A CORRECT
 declare -A SCORE
 CORRECT=""
 SCORE=""

 # First run: collecting data for a row
 cn=0
 for c in $COLUMNS; do
  cn=$((cn+1))
  j=${COL_J[$cn]}
  build_number=${COL_BUILD_NUMBER[$cn]}

  FWCLAUSE=" from tests where build_number=$build_number and prover='$j' and testcase='$t'"
  unset TIME
  unset RETVAL
  unset ACCEPTED
  unset ERRORTYPE
  unset RESULT
  TIME=`sqlite3 sqlite3db "select speed $FWCLAUSE"`
  RETVAL=`sqlite3 sqlite3db "select osresult $FWCLAUSE"`
  ACCEPTED=`sqlite3 sqlite3db "select accepted $FWCLAUSE"`
  ERRORTYPE=`sqlite3 sqlite3db "select errortype $FWCLAUSE"`
  RESULT=`sqlite3 sqlite3db "select result $FWCLAUSE"`

  RESULTCLASS=" class=\"o7\"" # <=0.2 FPS heavy
  CELLCOLOR="red!60"
  TEXTCOLOR="black!100"
  DIRNAMELENGTH=${#DIRNAME}
  FPS=""
  if [ "$ACCEPTED" = "" ]; then
   ALLGOOD=0
   if [ "$RESULT" = "" ]; then
    if [ "$ERRORTYPE" = 3 ]; then
    RESULTCLASS=" class=\"timeout\""
    CELLCOLOR="yellow!40"
    TIME="t/o"
    FPS="t/o"
    elif [ "$ERRORTYPE" = 0 ]; then
     RESULTCLASS=" class=\"undefined\""
     CELLCOLOR="yellow!25"
    else
     RESULTCLASS=" class=\"untested\""
     CELLCOLOR="white!25"
     fi
   else
    RESULTCLASS=" class=\"undefined\""
    CELLCOLOR="yellow!25"
    fi
   fi
  if [ "$ACCEPTED" = "0" ]; then
   RESULTCLASS=" class=\"error\""
   CELLCOLOR="black!100"
   TEXTCOLOR="black!0"
   ALLGOOD=0
   SCORE[$cn]="-1000000000000000" # -infty
   FPS=`echo "scale=2; 1000/$TIME" | bc -q | awk '{printf "%5.2f", $0}'`
   fi
  if [ "$ACCEPTED" = "1" ]; then
   VALUE=${CORRECT[$cn]}
   SCORE=${SCORE[$cn]}
   VALUE=$((VALUE+1))
   CORRECT[$cn]=$VALUE
   SCORE[$cn]=$((SCORE+20))
   FPS=`echo "scale=2; 1000/$TIME" | bc -q | awk '{printf "%5.2f", $0}'` # not elegant (repetition)
   if [ $TIME -lt 5000 ]; then
    RESULTCLASS=" class=\"o6\"" # >0.2 FPS heavy (very slow)
    CSVRESULT=1
    CELLCOLOR="red!40"
    SCORE[$cn]=$((SCORE+70))
    fi
   if [ $TIME -lt 1000 ]; then # >1 FPS jerky (slow)
    RESULTCLASS=" class=\"o5\""
    CELLCOLOR="orange!60"
    SCORE[$cn]=$((SCORE+95))
    fi
   if [ $TIME -lt 200 ]; then # >5 FPS moderate
    RESULTCLASS=" class=\"o4\""
    CELLCOLOR="cyan!60"
    SCORE[$cn]=$((SCORE+97))
    fi
   if [ $TIME -lt 83 ]; then # >12 FPS fast
    RESULTCLASS=" class=\"o3\""
    CELLCOLOR="green!40"
    SCORE[$cn]=$((SCORE+98))
    fi
   if [ $TIME -lt 50 ]; then # >20 FPS (very) fast
    RESULTCLASS=" class=\"o2\""
    CELLCOLOR="green!50"
    SCORE[$cn]=$((SCORE+99))
    fi
   if [ $TIME -lt 20 ]; then # >50 FPS (extremely) fast
    RESULTCLASS=" class=\"o1\""
    CELLCOLOR="green!60"
    SCORE[$cn]=$((SCORE+100))
    fi
   if [ $TIME -lt 5 ]; then
    ALLGOOD=0 # this is certainly some trivial case, so we ignore it
    fi
   fi
  RESULTCLASSDATA[$cn]=$RESULTCLASS
  CELLCOLORDATA[$cn]="$CELLCOLOR"
  TEXTCOLORDATA[$cn]="$TEXTCOLOR"
  RESULTDATA[$cn]="$RESULT"
  TIMEDATA[$cn]=$TIME
  FPSDATA[$cn]=$FPS
  done # All provers done for this tests

 # Second run: summarizing data in a row and generating HTML/LaTeX/R output
 cn=0
 for c in $COLUMNS; do
  cn=$((cn+1))
  j=${COL_J[$cn]}

  RESULTCLASS=${RESULTCLASSDATA[$cn]}
  CELLCOLOR=${CELLCOLORDATA[$cn]}
  TEXTCOLOR=${TEXTCOLORDATA[$cn]}
  RESULT=${RESULTDATA[$cn]}
  if [ "$RESULT" = undefined -o "$RESULT" = "?" ]; then
   RESULT=""
   fi
  TIME=${TIMEDATA[$cn]}
  FPS=${FPSDATA[$cn]}
  if [ "$ALLGOOD" = 1 ]; then
   ALLGOOD_SUM=$((ALLGOOD_SUM+TIME))
   ALLGOOD_NO=$((ALLGOOD_NO+1))
   fi

  # Find the degree of the polynomial:
  if [ "$RESULT" != "" ]; then
   HTMLRESULT=`echo "result = [$RESULT]
sy = result[0]
sx = result[1]
def m(x,y):
    if x > sx or y > sy or x < 1 or y < 1:
        return 0
    return result[1+(sx*(y-1))+x]

for i in range(sx+sy,0,-1):
    for j in range(0,i+1):
        if m(i-j,j) != 0:
            print(i-2)
            exit()

print(0)
# actually it might be -inf" | python`
  else
   HTMLRESULT=""
   fi

  echo "<td$RESULTCLASS>$HTMLRESULT</td><td$RESULTCLASS>$FPS</p></td>" >> $MYDIR/$HTML
  # TeX related changes
  TEXRESULT=$HTMLRESULT
  if [ "$TIME" = timeout ]; then
   TIME="t/o"
   FPS="t/o"
   fi
  echo "& \cellcolor{$CELLCOLOR}\textcolor{$TEXTCOLOR}{$TEXRESULT} & \cellcolor{$CELLCOLOR}{\textcolor{$TEXTCOLOR}{$FPS}} " >> $MYDIR/$TEX
  done

 echo "</tr>" >> $MYDIR/$HTML
 echo "\\\\ \\hline" >> $MYDIR/$TEX
 done # All tests done

# Summary
echo "<tr><td class=\"summary\" colspan=\"2\"><b>Summary (of $TESTS)</b></td>" >> $MYDIR/$HTML
echo "{\bf Total (of $TESTS)}" >> $MYDIR/$TEX
ALLGOOD_MEAN=$((ALLGOOD_SUM/ALLGOOD_NO))

cn=0
for c in $COLUMNS; do
 cn=$((cn+1))
 j=`echo $c | cut -f1 -d,`
 VALUE=${CORRECT[$cn]}
 if [ "$VALUE" = "" ]; then
  VALUE=0
  fi
 SCORE=${SCORE[$cn]}
 if [ "$SCORE" = "" ]; then
  SCORE=0
  fi
 if [ "${SCORE:0:1}" = "-" ]; then
  SCORE=error
  fi
 echo "<td class=\"summary\" colspan=\"2\"><b>$VALUE</b><br>$SCORE</td>" >> $MYDIR/$HTML
 echo "&\multicolumn{2}{c|}{\bf $VALUE}" >> $MYDIR/$TEX

 done
echo "</tr></table>" >> $MYDIR/$HTML

echo "</tr>" >> $MYDIR/$HTML
echo "\\\\ \\hline" >> $MYDIR/$TEX

echo "</body></html>" >> $MYDIR/$HTML
echo "\end{longtable}
}
\end{document}" >> $MYDIR/$TEX

echo -e "$TESTS tests done.\033[K"
